From 0eb096334e73642bb9b274289b7916ea00298d3a Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 27 Oct 1999 23:36:44 +0000 Subject: [PATCH] New function to threshold a pixbuf's alpha channel into a bitmap. 1999-10-27 Federico Mena Quintero * src/gdk-pixbuf-render.c (gdk_pixbuf_render_threshold_alpha): New function to threshold a pixbuf's alpha channel into a bitmap. * src/gdk-pixbuf.c (gdk_pixbuf_new): Fixed so that it will contemplate future extensions to ArtPixBuf's formats. * src/io-png.c (png_info_callback): Use the new API of gdk_pixbuf_new(). * src/gdk-pixbuf.h (gdk_pixbuf_get_height): Added some convenience macros to fetch the ArtPixBuf's fields. --- gdk-pixbuf/ChangeLog | 13 +++ gdk-pixbuf/Makefile.am | 5 +- gdk-pixbuf/gdk-pixbuf.c | 85 ++++++++---------- gdk-pixbuf/gdk-pixbuf.h | 42 ++++++++- gdk-pixbuf/gnome-canvas-pixbuf.c | 11 +++ gdk-pixbuf/io-png.c | 4 +- gdk/gdkpixbuf-render.c | 149 +++++++++++++++++++++++++++++++ 7 files changed, 252 insertions(+), 57 deletions(-) create mode 100644 gdk/gdkpixbuf-render.c diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog index b2bb2a6920..37e3697a0a 100644 --- a/gdk-pixbuf/ChangeLog +++ b/gdk-pixbuf/ChangeLog @@ -1,3 +1,16 @@ +1999-10-27 Federico Mena Quintero + + * src/gdk-pixbuf-render.c (gdk_pixbuf_render_threshold_alpha): New + function to threshold a pixbuf's alpha channel into a bitmap. + + * src/gdk-pixbuf.c (gdk_pixbuf_new): Fixed so that it will + contemplate future extensions to ArtPixBuf's formats. + + * src/io-png.c (png_info_callback): Use the new API of gdk_pixbuf_new(). + + * src/gdk-pixbuf.h (gdk_pixbuf_get_height): Added some convenience + macros to fetch the ArtPixBuf's fields. + 1999-10-27 Havoc Pennington * src/testpixbuf.c (main): Display the progressive load diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am index 10d807c25d..5db237704a 100644 --- a/gdk-pixbuf/Makefile.am +++ b/gdk-pixbuf/Makefile.am @@ -46,9 +46,10 @@ libgdk_pixbufincludedir = $(includedir)/gdk-pixbuf libgdk_pixbuf_la_SOURCES = \ gdk-pixbuf.c \ - gdk-pixbuf-loader.c \ + gdk-pixbuf-data.c \ gdk-pixbuf-io.c \ - gdk-pixbuf-data.c + gdk-pixbuf-loader.c \ + gdk-pixbuf-render.c libgdk_pixbuf_la_LDFLAGS = -version-info 1:0:0 diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c index 924f987bcc..4aacd3b171 100644 --- a/gdk-pixbuf/gdk-pixbuf.c +++ b/gdk-pixbuf/gdk-pixbuf.c @@ -100,63 +100,50 @@ gdk_pixbuf_new_from_art_pixbuf (ArtPixBuf *art_pixbuf) return pixbuf; } +/* Destroy notification function for gdk_pixbuf_new() */ +static void +free_buffer (gpointer user_data, gpointer data) +{ + free (data); +} + /** * gdk_pixbuf_new: - * @art_pixbuf: A libart pixbuf. - * - * Creates a &GdkPixbuf; magically sets the ArtPixFormat, rowstride, and creates - * the buffer. Use gdk_pixbuf_new_from_data() to do things manually. - * - * Return value: A newly-created &GdkPixbuf structure with a reference count of - * 1. Somewhat oddly, returns NULL if it can't allocate the buffer; this unusual - * behavior is needed because images can be very large. + * @format: Image format. + * @has_alpha: Whether the image should have transparency information. + * @bits_per_sample: Number of bits per color sample. + * @width: Width of image in pixels. + * @height: Height of image in pixels. + * + * Creates a new &GdkPixbuf structure and allocates a buffer for it. The buffer + * has an optimal rowstride. Note that the buffer is not cleared; you will have + * to fill it completely. + * + * Return value: A newly-created &GdkPixbuf, or NULL if not enough memory + * could be allocated for the image buffer. **/ GdkPixbuf * -gdk_pixbuf_new (gboolean has_alpha, int width, int height) +gdk_pixbuf_new (ArtPixFormat format, gboolean has_alpha, int bits_per_sample, + int width, int height) { - GdkPixbuf *pixbuf; + guchar *buf; + int channels; + int rowstride; + g_return_val_if_fail (format == ART_PIX_RGB, NULL); + g_return_val_if_fail (bits_per_sample == 8, NULL); g_return_val_if_fail (width > 0, NULL); - g_return_val_if_fail (height > 0, NULL); + g_return_val_if_fail (height > 0, NULL); - pixbuf = g_new (GdkPixbuf, 1); - pixbuf->ref_count = 1; - - if (has_alpha) { - art_u8* pixels; - int rowstride; - - /* FIXME, pick an optimal stride */ - rowstride = 4*width; - - pixels = art_alloc(rowstride*height); - - if (pixels == NULL) { - g_free(pixbuf); - return NULL; - } - - pixbuf->art_pixbuf = art_pixbuf_new_rgba(pixels, width, height, rowstride); - } else { - art_u8* pixels; - int rowstride; - - /* FIXME, pick an optimal stride */ - rowstride = 3*width; - - pixels = art_alloc(rowstride*height); - - if (pixels == NULL) { - g_free(pixbuf); - return NULL; - } - - pixbuf->art_pixbuf = art_pixbuf_new_rgb(pixels, width, height, rowstride); - } - - return pixbuf; + /* Always align rows to 32-bit boundaries */ + channels = has_alpha ? 4 : 3; + rowstride = 4 * ((channels * width + 3) / 4); -} - + buf = malloc (height * rowstride); + if (!buf) + return NULL; + return gdk_pixbuf_new_from_data (buf, format, has_alpha, width, height, rowstride, + free_buffer, NULL); +} diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h index 47fce21777..e05cc1838d 100644 --- a/gdk-pixbuf/gdk-pixbuf.h +++ b/gdk-pixbuf/gdk-pixbuf.h @@ -27,7 +27,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -50,6 +50,17 @@ struct _GdkPixbuf { +/* Convenience macros */ + +#define gdk_pixbuf_get_format(pixbuf) ((pixbuf)->art_pixbuf->format) +#define gdk_pixbuf_get_n_channels(pixbuf) ((pixbuf)->art_pixbuf->n_channels) +#define gdk_pixbuf_get_has_alpha(pixbuf) ((pixbuf)->art_pixbuf->has_alpha) +#define gdk_pixbuf_get_bits_per_sample(pixbuf) ((pixbuf)->art_pixbuf->bits_per_sample) +#define gdk_pixbuf_get_pixels(pixbuf) ((pixbuf)->art_pixbuf->pixels) +#define gdk_pixbuf_get_width(pixbuf) ((pixbuf)->art_pixbuf->width) +#define gdk_pixbuf_get_height(pixbuf) ((pixbuf)->art_pixbuf->height) +#define gdk_pixbuf_get_rowstride(pixbuf) ((pixbuf)->art_pixbuf->rowstride) + /* Reference counting */ void gdk_pixbuf_ref (GdkPixbuf *pixbuf); @@ -59,8 +70,10 @@ void gdk_pixbuf_unref (GdkPixbuf *pixbuf); GdkPixbuf *gdk_pixbuf_new_from_art_pixbuf (ArtPixBuf *art_pixbuf); -/* Create a "blank" pixbuf with an optimal rowstride and a new buffer */ -GdkPixbuf *gdk_pixbuf_new (gboolean has_alpha, int width, int height); +/* Create a blank pixbuf with an optimal rowstride and a new buffer */ + +GdkPixbuf *gdk_pixbuf_new (ArtPixFormat format, gboolean has_alpha, int bits_per_sample, + int width, int height); /* Simple loading */ @@ -70,7 +83,28 @@ GdkPixbuf *gdk_pixbuf_new_from_data (guchar *data, ArtPixFormat format, gboolean ArtDestroyNotify dfunc, gpointer dfunc_data); GdkPixbuf *gdk_pixbuf_new_from_xpm_data (const gchar **data); - +/* Rendering to a drawable */ + +typedef enum { + GDK_PIXBUF_ALPHA_BILEVEL, + GDK_PIXBUF_ALPHA_FULL +} GdkPixbufAlphaMode; + +void gdk_pixbuf_render_threshold_alpha (GdkPixbuf *pixbuf, GdkBitmap *bitmap, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int alpha_threshold); + +void gdk_pixbuf_render_to_drawable (GdkPixbuf *pixbuf, GdkDrawable *drawable, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + GdkPixbufAlphaMode alpha_mode, + int alpha_threshold, + GdkRgbDither dither, + int x_dither, int y_dither); + /* Transformations */ #if 0 GdkPixbuf *gdk_pixbuf_scale (const GdkPixbuf *pixbuf, gint w, gint h); diff --git a/gdk-pixbuf/gnome-canvas-pixbuf.c b/gdk-pixbuf/gnome-canvas-pixbuf.c index 90c9128c98..8195a608de 100644 --- a/gdk-pixbuf/gnome-canvas-pixbuf.c +++ b/gdk-pixbuf/gnome-canvas-pixbuf.c @@ -589,6 +589,7 @@ gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, double i_len, j_len; double scale[6], final[6]; guchar *buf; + GdkPixbuf *pixbuf; gcp = GNOME_CANVAS_PIXBUF (item); priv = gcp->priv; @@ -609,4 +610,14 @@ gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable, buf = g_new0 (guchar, width * height * 4); transform_pixbuf (buf, x, y, width, height, width * 4, priv->pixbuf, final); + + pixbuf = gdk_pixbuf_new_from_data (buf, ART_PIX_RGB, TRUE, + width, height, width * 4, + NULL, NULL); + + gdk_pixbuf_render_to_drawable (pixbuf, drawable, 0, 0, 0, 0, width, height, + GDK_RGB_DITHER_MAX, x, y); + + gdk_pixbuf_unref (pixbuf); + g_free (buf); } diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c index c6a8289c3e..6dacef8f48 100644 --- a/gdk-pixbuf/io-png.c +++ b/gdk-pixbuf/io-png.c @@ -153,7 +153,7 @@ image_load (FILE *f) png_structp png_ptr; png_infop info_ptr, end_info; gboolean failed = FALSE; - gint i, depth, ctype, inttype, passes, bpp; + gint i, ctype, bpp; png_uint_32 w, h; png_bytepp rows; guchar *pixels; @@ -360,7 +360,7 @@ png_info_callback (png_structp png_read_ptr, if (color_type & PNG_COLOR_MASK_ALPHA) have_alpha = TRUE; - lc->pixbuf = gdk_pixbuf_new(have_alpha, width, height); + lc->pixbuf = gdk_pixbuf_new(ART_PIX_RGB, have_alpha, 8, width, height); if (lc->pixbuf == NULL) { /* Failed to allocate memory */ diff --git a/gdk/gdkpixbuf-render.c b/gdk/gdkpixbuf-render.c new file mode 100644 index 0000000000..674da391ba --- /dev/null +++ b/gdk/gdkpixbuf-render.c @@ -0,0 +1,149 @@ +/* GdkPixbuf library - Rendering functions + * + * Copyright (C) 1999 The Free Software Foundation + * + * Author: Federico Mena-Quintero + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "gdk-pixbuf.h" + + + +/** + * gdk_pixbuf_render_threshold_alpha: + * @pixbuf: A pixbuf. + * @bitmap: Bitmap where the bilevel mask will be painted to. + * @src_x: Source X coordinate. + * @src_y: source Y coordinate. + * @dest_x: Destination X coordinate. + * @dest_y: Destination Y coordinate. + * @width: Width of region to threshold. + * @height: Height of region to threshold. + * @alpha_threshold: Opacity values below this will be painted as zero; all + * other values will be painted as one. + * + * Takes the opacity values in a pixbuf and thresholds them to produce a + * bi-level alpha mask that can be used as a clipping mask for a drawable. + **/ +void +gdk_pixbuf_render_threshold_alpha (GdkPixbuf *pixbuf, GdkBitmap *bitmap, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + int alpha_threshold) +{ + ArtPixBuf *apb; + GdkGC *gc; + GdkColor color; + int x, y; + guchar *p; + int start, start_status; + int status; + + g_return_if_fail (pixbuf != NULL); + apb = pixbuf->art_pixbuf; + + g_return_if_fail (apb->format == ART_PIX_RGB); + g_return_if_fail (apb->n_channels == 3 || apb->n_channels == 4); + g_return_if_fail (apb->bits_per_sample == 8); + + g_return_if_fail (bitmap != NULL); + g_return_if_fail (src_x >= 0 && src_x + width <= apb->width); + g_return_if_fail (src_y >= 0 && src_y + height <= apb->height); + + g_return_if_fail (alpha_threshold >= 0 && alpha_threshold <= 255); + + gc = gdk_gc_new (bitmap); + + if (!apb->has_alpha) { + color.pixel = (alpha_threshold == 255) ? 0 : 1; + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (bitmap, gc, TRUE, dest_x, dest_y, width, height); + gdk_gc_unref (gc); + return; + } + + color.pixel = 0; + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (bitmap, gc, TRUE, dest_x, dest_y, width, height); + + for (y = 0; y < height; y++) { + p = (apb->pixels + (y + src_y) * apb->rowstride + src_x * apb->n_channels + + apb->n_channels - 1); + + start = 0; + start_status = *p < alpha_threshold; + + for (x = 0; x < width; x++) { + status = *p < alpha_threshold; + + if (status != start_status) { + color.pixel = start_status ? 0 : 1; + gdk_gc_set_foreground (gc, &color); + gdk_draw_line (bitmap, gc, + start + dest_x, y + dest_y, + x - 1 + dest_x, y + dest_y); + + start = x; + start_status = status; + } + + p += apb->n_channels; + } + + color.pixel = start_status ? 0 : 1; + gdk_gc_set_foreground (gc, &color); + gdk_draw_line (bitmap, gc, + start + dest_x, y + dest_y, + x - 1 + dest_x, y + dest_y); + } + + gdk_gc_unref (gc); +} + +void +gdk_pixbuf_render_to_drawable (GdkPixbuf *pixbuf, GdkDrawable *drawable, + int src_x, int src_y, + int dest_x, int dest_y, + int width, int height, + GdkPixbufAlphaMode alpha_mode, + int alpha_threshold, + GdkRgbDither dither, + int x_dither, int y_dither) +{ + ArtPixBuf *apb; + ArtIRect dest_rect, req_rect, area_rect; + GdkBitmap *bitmap; + + g_return_if_fail (pixbuf != NULL); + apb = pixbuf->art_pixbuf; + + g_return_if_fail (apb->format == ART_PIX_RGB); + g_return_if_fail (apb->n_channels == 3 || apb->n_channels == 4); + g_return_if_fail (apb->bits_per_sample == 8); + + g_return_if_fail (drawable != NULL); + g_return_if_fail (src_x >= 0 && src_x + width <= apb->width); + g_return_if_fail (src_y >= 0 && src_y + height <= apb->height); + + + bitmap = gdk_pixmap_new (NULL, width, height, 1); +} -- 2.30.2